

import UIKit
import AVFoundation
@objc enum CameraViewType : Int
{
    case normal = 1
    case qr = 2
}

@objc protocol CameraViewDelegate{
    
    /// 代理
    /// - Parameters:
    ///   - imgData: 拍照或者相册完成的，得到的图片data
    ///   - resultString: 二维码扫描完成后识别的连接
    @objc func finished(_ imgData:NSData?, _ resultString:String)
    
    /// 设置镂空蒙版
    /// - Parameters:
    ///   - maskLayer: 镂空蒙版，可以设置蒙版非空心区域的颜色maskLayer.maskColor = clearColor，可以设置蒙版空心的位置maskLayer.claerFrame = xxx
    ///   - scanView: 扫描视图，与蒙版的空心区域重叠，可以在这个视图上自定义添加其他视图，设置扫描视图的frame,等同于设置蒙版的空心区域frame , 即maskLayer.claerFrame = xxx
    @objc func maskLayer(_ maskLayer:cameraMaskLayer, _ scanView:UIView)
    
    /// 设置扫描脉冲
    /// - Parameters:
    ///   - scanLine: 扫描脉冲线，可以设置扫描脉冲线的颜色
    ///   - animation: 扫描脉冲线的动画，可以自定义动画
    @objc func scanLine(_ scanLine:UIView, _ animation:CABasicAnimation)->Bool
}

extension CameraViewDelegate{
    func maskLayer(_ maskLayer:cameraMaskLayer, _ scanView:UIView){
    }
    func scanLine(_ scanLine:UIView, _ animation:CABasicAnimation) -> Bool{
        return false
    }
}
/// 二维码 / 拍照 / 相册
class CameraView: UIView {
   @objc weak var delegate:CameraViewDelegate?
    ///由他把输入输出结合在一起，并开始启动捕获设备（摄像头）
    @objc lazy var session:AVCaptureSession={return AVCaptureSession()}()
    ///摄像头
    lazy var device:AVCaptureDevice={return AVCaptureDevice.default(for: .video)}()!
    ///输入
    lazy var input:AVCaptureDeviceInput={return try? AVCaptureDeviceInput(device:self.device)}()!
    /// 输出图片
    lazy var imgOutput:AVCaptureStillImageOutput={return AVCaptureStillImageOutput()}()
    ///二维码输出
    lazy var output:AVCaptureMetadataOutput={
        let out = AVCaptureMetadataOutput()
        out.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        return out
    }()
    ///创建图像预览层，实时显示捕获到图像
    lazy var previewLayer:AVCaptureVideoPreviewLayer={
        let layer = AVCaptureVideoPreviewLayer(session: self.session)
        layer.frame = self.bounds
        layer.videoGravity = .resizeAspectFill
        self.layer.addSublayer(layer)
        return layer
    }()
    
    ///镂空蒙版
    lazy private var maskLayer:cameraMaskLayer = {
        let layer = cameraMaskLayer()
        layer.backgroundColor = UIColor.clear.cgColor
        layer.frame = self.bounds
        layer.delegate = layer
        self.layer.insertSublayer(layer, above: self.previewLayer)
        return layer
    }()
    
    ///镂空视图(扫描区域)
    lazy private var scanView:UIView={
        let view = UIView(frame: .zero)
        self.addSubview(view)
        self.bringSubviewToFront(view)
        return view
    }()
    
    ///扫描脉冲线
    lazy private var scanLine : UIView = {
        let w = self.maskLayer.clearFrame.size.width
        let view = UIView(frame:CGRect(x:0, y:0, width:w, height:10))
        view.gradient(["#005BBA".color(0),"#005BBA".color(0.8)], [0.4,1.0], .zero, CGPoint(x: 0, y: 1))
        view.isHidden = true
        self.scanView.addSubview(view)
        view.layer.removeAllAnimations()
        view.layer.add(self.scanLineAnimation, forKey: "positionAnimation")
        return view
    }()
    
    ///扫描脉冲线动画
    lazy private var scanLineAnimation:CABasicAnimation = {
        let w = self.maskLayer.clearFrame.size.width
        let h = self.maskLayer.clearFrame.size.height
        let anima = CABasicAnimation(keyPath:"position")
        anima.fromValue = NSValue.init(cgPoint:CGPoint(x:w / 2, y:0 ))
        anima.toValue = NSValue.init(cgPoint:CGPoint(x: w / 2, y:h))
        anima.duration = 3
        anima.repeatCount = 10000
        anima.isRemovedOnCompletion = false
        anima.autoreverses = true
        //anima.beginTime = CACurrentMediaTime() + 10
        return anima
    }()
    
   @objc var type:CameraViewType = .normal{
        didSet{
            if self.session.canAddInput(self.input){
                self.session.addInput(self.input)
            }
            switch type {
            case .normal:
                if self.session.canAddOutput(self.imgOutput){
                    self.session.addOutput(self.imgOutput)
                }
            case .qr:
                if self.session.canAddOutput(self.output){
                    self.session.addOutput(self.output)
                }
                self.output.metadataObjectTypes = self.output.availableMetadataObjectTypes
            }
            self.delegate?.maskLayer(self.maskLayer, self.scanView)
            self.maskLayer.clearFrame = self.scanView.frame != .zero ? self.scanView.frame : self.maskLayer.clearFrame
            
            self.scanLine.isHidden = !(self.delegate?.scanLine(self.scanLine,self.scanLineAnimation) ?? false)
            if self.scanLine.isHidden == false{
                self.scanLineAnimation.beginTime = CACurrentMediaTime() + 1
            }
            
            self.previewLayer.frame = self.bounds
            self.maskLayer.setNeedsDisplay()
            self.session.startRunning()
        }
    }
    /// 打开相册
    func openAlbum()
    {
        let vc = UIImagePickerController()
        vc.delegate = self
        vc.allowsEditing = true
        vc.sourceType = UIImagePickerController.SourceType.savedPhotosAlbum
        vc.modalPresentationStyle = .fullScreen
        self.currentVC().present(vc, animated:true)
    }
    
    ///拍照
    func takePhone()
    {
        let connection = self.imgOutput.connection(with: .video) ?? nil
        if connection == nil{
            return print("拍照失败!")
        }
        self.imgOutput.captureStillImageAsynchronously(from: connection!) { buff, error in
            if buff == nil {return }
            let imgData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buff!)
            self.delegate?.finished(imgData! as NSData, "")
            self.session.stopRunning()
        }
    }
    
    
    /// 切换闪光灯
    func flash(_ open:Bool)
    {
        if self.device.hasFlash{
            try? self.device.lockForConfiguration()
            self.device.torchMode = open ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
        }
    }
    
    ///切换摄像头
    func changeCamera()
    {
        let count = AVCaptureDevice.devices(for: .video).count
        if count < 2{
            print("只有一个摄像头")
            return
        }
        /// 另一个摄像头的位置
        let position:AVCaptureDevice.Position = self.input.device.position == .front ? .back : .front
        let subtype:CATransitionSubtype = position == .back ? .fromLeft : .fromRight
        let newCamera:AVCaptureDevice = self.cameraPosition(position)!
        
        ///镜头反转动画
        let animation = CATransition()
        animation.duration = 0.5
        animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeInEaseOut)
        animation.type = CATransitionType.init(rawValue:"oglFlip")
        animation.subtype = subtype///翻转方向
        
        //生成新的输入
        let newInput = try? AVCaptureDeviceInput.init(device: newCamera)
        self.previewLayer.add(animation, forKey: nil)
        if (newInput != nil) {
            self.session.beginConfiguration()
            if self.session.canAddInput(newInput!){
                self.session.removeInput(self.input)
                self.session.addInput(newInput!)
                self.input = newInput!
            }
            self.session.commitConfiguration()
        }
        
    }
    ///获取相机位置
    private func cameraPosition(_ position:AVCaptureDevice.Position)->AVCaptureDevice?
    {
        let devices = AVCaptureDevice.devices(for: .video)
        for device in devices {
            if device.position == position{return device}
        }
        return nil
    }
}

//MARK: - 相册代理 UIImagePickerControllerDelegate/UINavigationControllerDelegate
extension CameraView : UIImagePickerControllerDelegate , UINavigationControllerDelegate
{
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        let img : UIImage = info[UIImagePickerController.InfoKey.editedImage] as! UIImage
        let data = img.pngData()
        self.delegate?.finished(data! as NSData, "")
        picker.dismiss(animated: true) { }
    }
}

//MARK: - 扫描二维码代理 AVCaptureMetadataOutputObjectsDelegate
extension CameraView : AVCaptureMetadataOutputObjectsDelegate
{
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        if metadataObjects.count > 0{
            let obj = metadataObjects.last as? AVMetadataMachineReadableCodeObject ?? nil
            if obj == nil {return}
            let result = obj!.stringValue
            self.delegate?.finished(nil, result!)
            self.session.stopRunning()
        }
    }
}

@objc class cameraMaskLayer:CALayer,CALayerDelegate{
    ///空心区域 = 扫描区域
   @objc var clearFrame : CGRect = .zero
    ///蒙版颜色 =  非空心区域颜色，空心区域颜色 =  maskLayer.backgroundColor
   @objc var maskColor:UIColor = UIColor.init(red: 0.1, green: 0.1, blue: 0.1, alpha: 0.8)
    
    override func draw(in ctx: CGContext) {
        if self.clearFrame.size.width > 0 && self.clearFrame.size.height > 0{
            UIGraphicsBeginImageContextWithOptions(self.frame.size, true, 0)
            ///蒙版背景颜色
            ctx.setFillColor(self.maskColor.cgColor)
            ctx.fill(self.frame)
            ctx.clear(self.clearFrame)
        }
    }
}

